import subprocess
import sys
import PySimpleGUI as sg
import pyperclip

# 修复高DPI感知
if sys.platform == 'win32':
    try:
        import ctypes

        ctypes.OleDLL('shcore').SetProcessDpiAwareness(1)
    except (ImportError, AttributeError, OSError):
        pass


def uninstall(sel_app):
    try:
        if notfoundAppx(sel_app):
            print(f"应用 '{sel_app}' 不存在")
        else:
            print(f"应用 '{sel_app}' 存在", "开始卸载...")
            # uninstall_command = f"Get-AppxPackage -Name '*{sel_app}*' | Remove-AppxPackage"
            uninstall_command = f"Get-AppxPackage -Name '*{sel_app}*' | Remove-AppxPackage"
            result = subprocess.run(["powershell", uninstall_command], capture_output=True, text=True)
            if result.returncode == 0:
                print("卸载命令执行成功！")
            else:
                print('命令执行失败，参考：')
                print(result.stdout)
                print(result.stderr)
            if notfoundAppx(sel_app):
                print(sel_app, '确认已卸载!')
                window[sel_app].update(text_color='red')
            else:
                print('应用还存在，似乎未卸载成功')
    except Exception as e:
        print(f"卸载应用时出现错误： {e}")
    print('\n')


def notfoundAppx(app_name):  # 检查指定的应用程序是否不存在
    # 定义一个命令，用于搜索指定应用程序
    command = f"Get-AppxPackage -Name '*{app_name}*'"
    try:
        # 使用PowerShell运行命令，并将输出捕获到check_result中
        check_result = subprocess.run(["powershell", command], capture_output=True, text=True)
        # 如果输出为空，则表示应用程序不存在
        if check_result.stdout.strip() == "":
            return True
        else:
            return False
    except Exception as e:
        # 如果出现异常，则打印异常信息
        print(f"An error occurred: {e}")


def getColor(curr_name):
    if curr_name in warn_list:
        return 'purple'
    elif curr_name in name_dict.keys():
        return '#006600'
    elif curr_name in dev_list:
        return 'blue'
    else:
        return 'black'


def getName(name):  # 获取推荐列表中的名字
    # 判断name是否在recom_dict中
    if name in name_dict.keys():
        # 如果在，返回recom_dict中的值
        return name_dict[name]
    else:
        # 如果不在，返回name
        return name


def tidy(name_list):
    recom = []
    noml = []
    dev = []
    warn = []

    for x in name_list:
        if x in name_dict.keys():
            recom.append(x)
        elif x in warn_list:
            warn.append(x)
        elif x in dev_list:
            dev.append(x)
        else:
            noml.append(x)
    recom.sort()
    noml.sort()
    dev.sort()
    warn.sort()
    print('推荐卸载', len(recom))
    print('第三方', len(dev))
    print('不建议卸载', len(warn))
    return recom + noml + dev + warn


name_dict = {
    "Microsoft.Print3D": "打印3D",
    "Microsoft.WindowsCamera": "相机",
    "Microsoft.GetHelp": "获取帮助",
    "Microsoft.WindowsFeedbackHub": "Windows反馈中心",
    "Microsoft.Getstarted": "入门提示",
    "Microsoft.MicrosoftOfficeHub": "Office Hub",
    "Microsoft.ZuneMusic": "Zune音乐",
    "Microsoft.ZuneVideo": "Zune视频",
    "Microsoft.Microsoft3DViewer": "3D查看器",
    "Microsoft.MSPaint": "画图",
    "Microsoft.Paint": "画图",
    "Microsoft.MicrosoftStickyNotes": "便签",
    "Microsoft.Wallet": "钱包",
    "Microsoft.WindowsMaps": "地图",
    "Microsoft.Messaging": "消息",
    "Microsoft.BingWeather": "天气",
    "Microsoft.People": "人脉",
    "Microsoft.YourPhone": "你的手机",
    "Microsoft.OneConnect": "OneConnect",
    "Microsoft.MixedReality.Portal": "混合现实门户",
    "Microsoft.Xbox.TCUI": "Xbox TCUI",
    "Microsoft.XboxApp": "XboxApp",
    "Microsoft.XboxGameOverlay": "XboxGameOverlay",
    "Microsoft.XboxGamingOverlay": "XboxGamingOverlay",
    "Microsoft.XboxSpeechToTextOverlay": "Xbox语音转文本叠加层",
    "Microsoft.XboxIdentityProvider": "Xbox身份提供者",
    "Microsoft.GamingApp": "GamingApp",
    "Microsoft.3DBuilder": "3D建模",
    "Microsoft.MicrosoftSolitaireCollection": "微软纸牌游戏合集",
    "Microsoft.Office.OneNote": "OneNote",
    "Microsoft.SkypeApp": "Skype应用",
    "Microsoft.Windows.Photos": "照片",
    "Microsoft.WindowsAlarms": "闹钟",
    "Microsoft.windowscommunicationsapps": "邮件和日历",
    "microsoft.windowscommunicationsapps": "邮件和日历",
    "Microsoft.MicrosoftEdge.Stable": "Edge浏览器稳定版",
    "Microsoft.Todos": "Todos待办事项",
    "Microsoft.BingNews": "资讯",
    "Clipchamp.Clipchamp": "Clipchamp视频编辑器",
    "Microsoft.549981C3F5F10": "Cortana",
    "Microsoft.WindowsCalculator": "计算器",
    "Microsoft.WindowsSoundRecorder": "录音机",
    "Microsoft.ScreenSketch": "屏幕截图",
    "Microsoft.PowerAutomateDesktop": "PowerAutomate自动任务"
}
warn_list = ['Microsoft.WindowsStore', 'Microsoft.WindowsTerminal', 'Microsoft.DesktopApplnstaller']

print("正在获取包信息，等待系统响应...")
getapp_pscmd = 'powershell "Get-AppxPackage | Select-Object -Property Name, IsFramework, NonRemovable, SignatureKind,PackageFullName"'
echo = ""
try:
    echo = subprocess.check_output(getapp_pscmd).decode("utf-8")
except Exception as e:
    print(f"获取包信息时出现错误： {e}\n请检查是否安装powershell")
echo_list = list(filter(None, echo.split("\r\n\r\n")))
num = len(echo_list)
if num > 0:
    print(f"包数量: {num}")
else:
    print("没有找到任何包,请检查是否以管理员权限运行")

# 创建一个空列表，用于存储包的信息
pkg_list = []  # 包列表
name_list = []
dev_list = []
# 遍历echo_list中的每个元素（即每个包的信息）
for echo_item in echo_list:
    # 将字符串按照换行符进行分割，得到一个列表
    lines = str(echo_item).split("\n")
    # 创建一个空字典，用于存储当前包的信息
    appinfdic = {}
    # 遍历lines中的每个元素（即当前包的一行信息）
    for x in lines:
        # 如果当前行包含冒号，说明该行是一个键值对
        if ":" in x:
            # 使用split方法将字符串按照冒号进行分割，得到一个列表，其中第一个元素为键，第二个元素为值
            k, v = x.split(":", 1)
            # 将键和值去除首尾空格后存入字典
            appinfdic[k.strip()] = v.strip()
    # 只添加"NonRemovable"为"False"的包到包列表中
    if appinfdic.get("NonRemovable") == "False" and appinfdic.get("IsFramework") == "False":
        pkg_list.append(appinfdic)  # 将一个包字典存入包列表
        name_list.append(appinfdic.get('Name'))
    if appinfdic.get("SignatureKind") == "Developer":
        dev_list.append(appinfdic.get('Name'))

name_list = tidy(name_list)  # 推荐列表中的应用置顶
print("可卸载的非框架应用", len(name_list))

# 界面布局
sg.set_options(font=('微软雅黑', 8))
sg.theme('SystemDefaultForReal')
row_cap = 4 if len(name_list) > 33 else 3

frame_layout = []
row_layout = []

for i, capp in enumerate(name_list):
    if i % row_cap == 0:  # 如果当前是新行的开始
        row_layout = []

    column_layout = [[  # 创建单个应用的Column布局
        sg.Checkbox(getName(capp), size=(30, 1), key=capp, text_color=getColor(capp)),
        sg.Button('详情', key=f'btinfo-{capp}'),
        sg.Button('卸载', key=f'button-{capp}')
    ]]

    row_layout.append(sg.Column(column_layout))  # 将该Column添加到当前行布局

    # 当达到每行的最大元素数或者处理到最后一个应用时，将当前行布局添加到主布局中
    if len(row_layout) == row_cap or i == len(name_list) - 1:
        frame_layout.append(row_layout)

layout = [  # 创建一个表格布局，其中包含表格布局和提交和取消按钮
    [sg.Frame('可卸载的非框架应用', frame_layout)],
    [
        sg.Button('全选'),
        sg.Button('反选'),
        sg.Button('全不选'),
        sg.Button('复制名称'),
        # sg.Button('显示信息'),
        sg.Button('推荐卸载', button_color=('white', 'springgreen4')),
        sg.Button('一键卸载', button_color=('white', 'firebrick3')),
        sg.Button('退出'),

        sg.Text('第三方', text_color='blue'),
        sg.Text('不推荐卸载', text_color='purple'),
        sg.Text('已卸载', text_color='red'),
    ]
]

# sg.theme('SystemDefaultForReal')
window = sg.Window('WinAppsUninstaller_v0.8.7', layout)

while True:  # 添加事件循环
    event, values = window.read()

    if event in (sg.WIN_CLOSED, '退出'):
        break

    if event.startswith('button-'):
        app_name = event.split('-')[1]
        uninstall(app_name)

    if event.startswith('btinfo-'):
        app_name = event.split('-')[1]
        powershell_command = f"Get-AppxPackage {app_name} | Select-Object Name, PackageFullName, Version, InstallLocation, Dependencies"
        echo = subprocess.check_output(["powershell", powershell_command]).decode("utf-8")
        print(echo)

    if event == '全选':
        for aapp in name_list:
            window[aapp].update(value=True)

    if event == '反选':
        for app in name_list:
            window[app].update(value=not window[app].get())

    if event == '全不选':
        for app in name_list:
            window[app].update(value=False)

    if event == '一键卸载':
        selected_apps = [app for app in name_list if window[app].get()]
        if sg.popup_yes_no(f'确定要卸载选中的{len(selected_apps)}个应用吗?') == 'Yes':
            for app in selected_apps:
                uninstall(app)
            sg.popup('卸载完成', f'已卸载{len(selected_apps)}个应用')

    if event == '复制名称':
        selected_apps = [app for app in name_list if window[app].get()]
        pyperclip.copy('\n'.join(selected_apps))
        print(selected_apps)
        print('已复制到剪切板', len(selected_apps), '个应用')

    if event == '推荐卸载':
        for app in name_list:
            if app in name_dict.keys():
                window[app].update(value=True)
window.close()
